package org.exteen.tag.core;

import java.util.Arrays;
import java.util.Collections;

import org.exteen.ExteenException;
import org.exteen.exec.ExteenContext;
import org.exteen.exec.ExteenPathChangeException;
import org.exteen.exec.Tag;
import org.exteen.output.ExteenStream;
import org.exteen.parser.Node;

public class ForEachTag extends Tag {
    // [begin] end [step] [indexVar]
    // [var] items [begin] [indexVar]
    public void doTag(ExteenContext ctx, ExteenStream stream) {
        ctx.markWithTag(this);
        if (ctx.getNode().getAttribute("end")!=null) {
            doBeginEndLoop(ctx, stream);
        } else {
            doItemsLoop(ctx, stream);
        }
    }

    private void doBeginEndLoop(ExteenContext ctx, ExteenStream stream) {

        long begin = ctx.parseAttributeAsLong("begin", 0);
        long end = ctx.parseAttributeAsLong("end", 0);
        long step = ctx.parseAttributeAsLong("step", 1);
        String indexVar = ctx.getVarAttrValue("indexVar");
        if (step==0) {
            throw new ExteenException("Loop step may not be 0");
        }
        if (step>0) {
            while (begin<=end) {
                if (indexVar!=null) {
                    ctx.set(indexVar, begin, false);
                }
                try {
                    super.doTag(ctx, stream);
                } catch (ExteenPathChangeException epxe) {
                    if (epxe.type==ExteenPathChangeException.Type.BREAK) {
                        break; 
                    }
                }
                begin += step;
            }
        } else {
            while (begin>=end) {
                if (indexVar!=null) {
                    ctx.set(indexVar, begin, false);
                }
                try {
                    super.doTag(ctx, stream);
                } catch (ExteenPathChangeException epxe) {
                    if (epxe.type==ExteenPathChangeException.Type.BREAK) {
                        break;
                    }
                }
                begin += step;
            }
        }
    }

    private void doItemsLoop(ExteenContext ctx, ExteenStream stream) {
        Node node = ctx.getNode();
        long begin = ctx.parseAttributeAsLong("begin", 0);
        String indexVar = ctx.getVarAttrValue("indexVar");
        String var = ctx.getVarAttrValue("var");
        Object items = node.getAttributeValue("items", ctx);
        if (items==null) {
            throw new ExteenException("Value of items attribute in forEach must not be null");
        }
        Iterable<?> iterable = null;
        if (items instanceof Iterable) {
            iterable = (Iterable<?>) items;
        } else if (items.getClass().isArray()) {
            iterable = Arrays.asList((Object[]) items);
        } else {
            iterable = Collections.singletonList(items);
        }
        for (Object o: iterable) {
            if (indexVar!=null) {
                ctx.set(indexVar, begin, false);
            }
            if (var!=null) {
                ctx.set(var, o, false);
            }
            try {
                super.doTag(ctx, stream);
            } catch (ExteenPathChangeException epxe) {
                if (epxe.type==ExteenPathChangeException.Type.BREAK) {
                    break;
                }
            }
        }
    }


}